# map.rb
# created by: Dan Alexander
# date: 3/6/2011
# license: New BSD License
#
# Map
# A basic map class to handle drawing the world.

include Rubygame

class Map
	attr_accessor :tiles
	attr_accessor :width
	attr_accessor :height
	attr_accessor :legend
	attr_accessor :map_loaded
	attr_accessor :monsters
	attr_accessor :items
	attr_accessor :players
	
	def initialize()
		@map_loaded = false
		#tiles is now a hash, which gets it's
		#information from the server as a json string
		@tiles = Hash.new
		
		@height
		@width
		
		@tile_image
		
		#create the entities hash - this holds all of the characters
		@monsters = Hash.new
		
		#add the player to the players
		@players = Hash.new
		
		#create the items hash - this holds all of the items
		@items = Hash.new
		
		#legend for the ascii to image
		#ascii is key, image is value
		#"#" = "wall"
		@legend = Hash.new
		File.open("legend.dat",'r') do |file|
			while line = file.gets
				line2 = line.strip!
				if line2 != nil then line = line2 end
				line = line.gsub("\"","")
				@legend[line.split(",")[0]] = line.split(",")[1]
			end
		end
	end
	
	#this creates the map from a json string passed in
	def load_json_map(json)
		if $debug then puts "BUILDING MAP FROM JSON" end
		@map_loaded = false
		
		@players = Hash.new
		
		if $debug then puts "PARSING JSON..." end
		test = Hash.new
		test = JSON.parse(json)
		
		if $debug then puts "SETTING TILES..." end
		@tiles = test["map"]
		@height = @tiles["height"]
		if $debug then puts "height: " + @height.to_s() end
		@width = @tiles["width"]
		if $debug then puts "width: " + @width.to_s() end
		
		if $debug then puts "filling floor tiles..." end
		fill_floor
		
		#build the image
		if $debug then puts "creating map image..." end
		@tile_image = Surface.new([@width*32,@height*32])
		if $debug then puts @tile_image.w.to_s() + "," + @tile_image.h.to_s() end
		for y in 0..@height-1
			for x in 0..@width-1
				$resman.get_tile(get_image(x,y)).blit @tile_image, [x*32,y*32,32,32]
			end
		end
		
		@map_loaded = true
		if $debug then puts "DONE BUILDING FROM JSON" end
	end
	
	#this function is used to fill the floor of the hash
	#received from the server.
	def fill_floor
		startx = @tiles["spawn"]["main"]["x"]
		starty = @tiles["spawn"]["main"]["y"]
		
		fill_floor_rec([startx,starty],nil," ")
		
		#Flood-fill (node, target-color, replacement-color):
		#1. If the color of node is not equal to target-color, return.
		#2. Set the color of node to replacement-color.
		#3. Perform Flood-fill (one step to the west of node, target-color, replacement-color).
		#Perform Flood-fill (one step to the east of node, target-color, replacement-color).
		#Perform Flood-fill (one step to the north of node, target-color, replacement-color).
		#Perform Flood-fill (one step to the south of node, target-color, replacement-color).
		#4. Return
		
	end
	
	def fill_floor_rec(node,target,replacement)
		x = Integer(node[0])
		y = Integer(node[1])
		#check for target
		if @tiles[node[0].to_s()][node[1].to_s()] != nil then return end
			
		@tiles[node[0].to_s()][node[1].to_s()] = Hash.new
		@tiles[node[0].to_s()][node[1].to_s()]["ascii"] = replacement
		
		#go one tile in each direction
		fill_floor_rec([x+1,y],target,replacement) #east
		fill_floor_rec([x-1,y],target,replacement) #west
		fill_floor_rec([x,y-1],target,replacement) #north
		fill_floor_rec([x,y+1],target,replacement) #south
	
	end
	
	def player
		index = -1
		for i in 0..@players.length
			if @players[i] != nil && @players[i]["name"] == $player_name
				index = i
			end
		end
		
		if index >= 0
			obj = @players[index]
		else
			obj = nil
		end
	end
	
	def get_player_pos
		pos = Array.new
		pos[0] = @tiles["spawn"]["main"]["x"]
		pos[1] = @tiles["spawn"]["main"]["y"]
		pos
	end
	
	#returns the name of the image
	#needed from the resource manager
	#for the tile at <x>,<y>
	def get_image(x,y)
		if @tiles[y.to_s()] == nil || @tiles[y.to_s()][x.to_s()] == nil
			key = "blank"
		else
			key = @tiles[y.to_s()][x.to_s()]["ascii"]
		end
		@legend[key]
	end
	
	#returns the tile at position x,y
	def get_tile(x,y)
		@tiles[y.to_s()][x.to_s()]
	end
	
	#return the map's width
	def w
		@width
	end
	
	#return the map's height
	def h
		@height
	end
	
	def draw screen
		if @map_loaded == false then return end

		wid = 32 #width of a tile
		hite = 32 #height of a tile
		w = @width #how many tiles wide is the tilemap
		h = @height #how many tiles high is the tilemap
		
		tiles_across = screen.w / wid #how many tiles can we fit across the screen
		tiles_down = screen.h / hite  #how many tiles can we fit down the screen
	
		#first, make sure x,y,w,h all fit within the bounds of the tilemap

		viewWidth = tiles_across
		viewHeight = tiles_down
		
		if player != nil
			startX = player["x"] - viewWidth / 2
			startY = player["y"] - viewHeight / 2
		else
			startX = 0
			startY = 0
		end
		
		if startX < 0
			startX = 0;
		elsif startX + tiles_across >= w
			startX = w - tiles_across
		end
		if startY < 0
			startY = 0
		elsif startY + tiles_down >= h
			startY = h - tiles_down
		end
		
		drawX = 0
		drawY = 0

		@tile_image.blit screen, [0,0], [startX*32,startY*32,screen.w,screen.h]
		
		for yy in startY..startY + viewHeight-1
			break if yy >= h
			for xx in startX..startX + viewWidth-1	
				break if xx >= w
				#draw players here
				@players.each do|plyr|
					if plyr["x"] == xx && plyr["y"] == yy
						$resman.get_tile(plyr["class"]).blit screen, [drawX*wid, drawY*hite]
					end
				end
				#draw monsters here
				@monsters.each do|monster|
					if monster["x"] == xx && monster["y"] == yy
						$resman.get_tile(monster["type"]).blit screen, [drawX*wid, drawY*hite]
					end
				end
				drawX += 1
			end
			drawY += 1
			drawX = 0
		end
	end
end